﻿using System;
using System.Collections.Generic;

namespace BizElements.Core
{
    /// <summary>Entity property binder factory creates <see cref="IEntityPropertyBinder"/> objects for provided entities. You may register custom binders.</summary>
    /// <remarks><para>By default, the factory checks if an entity implements <see cref="IEntityPropertyBinder"/> interface. 
    /// If not then a default or custom <see cref="IEntityPropertyBinder"/> object is created that binds entity properties.</para></remarks>
    public static class EntityPropertyBinderFactory
    {
        static readonly Type DefaultBinderClass = typeof(EntityPropertyBinder);
        static readonly Dictionary<string, Type> BinderMap = new Dictionary<string, Type>();

        /// <summary>Registers custom binder for entities mapped to the specified table/view name.</summary>
        /// <typeparam name="T">A class that implements <see cref="IEntityPropertyBinder"/> interface and has a default/parameterless constructor.</typeparam>
        /// <param name="tableName">Table/view name.</param>
        public static void RegisterBinder<T>(string tableName)
            where T : class, IEntityPropertyBinder, new()
        {
            BinderMap[tableName] = typeof(T);
        }

        /// <summary>Gets binder object that provides property binding services for the specified entity.</summary>
        /// <param name="entity">Entity. If it implements IEntityPropertyBinder then it is returned by the method.</param>
        /// <returns>Binder.</returns>
        public static IEntityPropertyBinder GetBinder(IEntity entity)
        {
            // Entity may handle binding on its own. E.g. classes which derive from EntityModelBase.
            IEntityPropertyBinder binder = entity as IEntityPropertyBinder;
            if (binder != null)
                return binder;

            Type binderClass;
            BinderMap.TryGetValue(entity.Table.TableName, out binderClass);
            if (binderClass == null)
                binderClass = DefaultBinderClass;

            binder = (IEntityPropertyBinder)Activator.CreateInstance(binderClass);
            binder.BoundEntity = entity;
            return binder;
        }
    }
}
